package transparent.core;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.Ansi.Erase;
import org.fusesource.jansi.AnsiConsole;
import org.fusesource.jansi.Ansi.Color;
import jline.CandidateListCompletionHandler;
import jline.Completor;
import jline.ConsoleReader;
public class Console
{
private static Command root = new Command("",
new ModulesCommand(),
new TasksCommand(),
new HistoryCommand(),
new ExitCommand(),
new TriggersCommand(),
new MigrateCommand(),
new TestServerCommand(),
new ImageQueueCommand());
private static ReentrantLock consoleLock = new ReentrantLock();
private static int nestedLock = 0;
private static boolean isReading = false;
private static final String PROMPT = "$ ";
/* ANSI string codes for text formatting */
public static final String BOLD = new Ansi().bold().toString();
public static final String UNBOLD = new Ansi().boldOff().toString();
public static final String RED = new Ansi().fg(Color.RED).toString();
public static final String BLUE = new Ansi().fg(Color.BLUE).toString();
public static final String GRAY = new Ansi().fgBright(Color.BLACK).toString();
public static final String DEFAULT = new Ansi().fg(Color.DEFAULT).toString();
public static final String ERASE = new Ansi().eraseLine(Erase.ALL).toString();
private static List<Token> tokens = new ArrayList<Token>();
private static ConsoleReader in = null;
private static final ConsoleCompletor completor = new ConsoleCompletor();
private static AtomicBoolean historyEnabled = new AtomicBoolean(true);
public static Boolean parseBoolean(String token)
{
if (token.equals("1"))
return true;
else if (token.equals("0"))
return false;
String lower = token.toLowerCase();
if (lower.equals("true") || lower.equals("on")
|| lower.equals("yes") || lower.equals("y"))
return true;
else if (lower.equals("false") || lower.equals("off")
|| lower.equals("no") || lower.equals("n"))
return false;
return null;
}
public static void flush() {
AnsiConsole.out.flush();
}
public static void lockConsole() {
if (!consoleLock.isHeldByCurrentThread())
consoleLock.lock();
else nestedLock++;
if (isReading && in != null) {
AnsiConsole.out.print(ERASE);
AnsiConsole.out.print(new Ansi().cursorLeft(
in.getCursorBuffer().cursor + PROMPT.length()));
}
}
public static void unlockConsole() {
try {
if (isReading && in != null)
in.restoreLine();
} catch (IOException e) { }
if (nestedLock == 0)
consoleLock.unlock();
else nestedLock--;
}
public static void write(byte[] data) throws IOException
{
lockConsole();
AnsiConsole.out.write(data);
unlockConsole();
}
public static void print(boolean b)
{
lockConsole();
AnsiConsole.out.print(b);
unlockConsole();
}
public static void print(char c)
{
lockConsole();
AnsiConsole.out.print(c);
unlockConsole();
}
public static void print(int i)
{
lockConsole();
AnsiConsole.out.print(i);
unlockConsole();
}
public static void print(long l)
{
lockConsole();
AnsiConsole.out.print(l);
unlockConsole();
}
public static void print(float f)
{
lockConsole();
AnsiConsole.out.print(f);
unlockConsole();
}
public static void print(double d)
{
lockConsole();
AnsiConsole.out.print(d);
unlockConsole();
}
public static void print(char[] c)
{
lockConsole();
AnsiConsole.out.print(c);
unlockConsole();
}
public static void print(String s)
{
lockConsole();
AnsiConsole.out.print(s);
unlockConsole();
}
public static void print(Object obj)
{
lockConsole();
AnsiConsole.out.print(obj);
unlockConsole();
}
public static void println()
{
lockConsole();
AnsiConsole.out.println();
unlockConsole();
}
public static void println(boolean b)
{
lockConsole();
AnsiConsole.out.println(b);
unlockConsole();
}
public static void println(char c)
{
lockConsole();
AnsiConsole.out.println(c);
unlockConsole();
}
public static void println(int i)
{
lockConsole();
AnsiConsole.out.println(i);
unlockConsole();
}
public static void println(long l)
{
lockConsole();
AnsiConsole.out.println(l);
unlockConsole();
}
public static void println(float f)
{
lockConsole();
AnsiConsole.out.println(f);
unlockConsole();
}
public static void println(double d)
{
lockConsole();
AnsiConsole.out.println(d);
unlockConsole();
}
public static void println(char[] c)
{
lockConsole();
AnsiConsole.out.println(c);
unlockConsole();
}
public static void println(String s)
{
lockConsole();
AnsiConsole.out.println(s);
unlockConsole();
}
public static void println(Object obj)
{
lockConsole();
AnsiConsole.out.println(obj);
unlockConsole();
}
public static void format(String format, Object ... args) {
lockConsole();
AnsiConsole.out.format(format, args);
unlockConsole();
}
public static void format(Locale l, String format, Object ... args) {
lockConsole();
AnsiConsole.out.format(l, format, args);
unlockConsole();
}
public static void append(CharSequence csq, int start, int end) {
lockConsole();
AnsiConsole.out.append(csq, start, end);
unlockConsole();
}
public static void printWarning(String className,
String methodName, String message)
{
commandWarning(className + '.' + methodName, message);
}
public static void printError(String className,
String methodName, String message)
{
commandError(className + '.' + methodName, message);
}
public static void printError(String className,
String methodName, String message, Exception exception)
{
commandError(className + '.' + methodName, message, exception);
}
private static void commandWarning(String command, String message)
{
lockConsole();
AnsiConsole.out.print(BOLD);
AnsiConsole.out.print(command + " WARNING: ");
AnsiConsole.out.print(UNBOLD);
AnsiConsole.out.print(message);
AnsiConsole.out.println();
unlockConsole();
}
private static void commandError(String command, String message)
{
lockConsole();
AnsiConsole.out.print(RED + BOLD);
AnsiConsole.out.print(command + " ERROR: ");
AnsiConsole.out.print(UNBOLD + DEFAULT);
AnsiConsole.out.print(message);
AnsiConsole.out.println();
unlockConsole();
}
private static void commandError(String command, String message, Exception exception)
{
lockConsole();
AnsiConsole.out.print(RED + BOLD);
AnsiConsole.out.print(command + " ERROR: ");
AnsiConsole.out.print(UNBOLD + DEFAULT);
AnsiConsole.out.print(message);
if (exception != null) {
if (message.length() > 0)
AnsiConsole.out.print(' ');
AnsiConsole.out.print(exception.getClass().getSimpleName() + " thrown. ");
String exceptionMessage = exception.getMessage();
AnsiConsole.out.print(GRAY);
if (exceptionMessage != null)
AnsiConsole.out.print(exceptionMessage);
StringWriter writer = new StringWriter();
PrintWriter wrapper = new PrintWriter(writer);
exception.printStackTrace(wrapper);
wrapper.flush();
AnsiConsole.out.print(writer.toString());
wrapper.close();
AnsiConsole.out.print(DEFAULT);
}
AnsiConsole.out.println();
unlockConsole();
}
private static void escape(StringBuilder token, char escapeChar)
{
switch (escapeChar) {
case '"':
token.append('"');
break;
case '\'':
token.append('"');
break;
case ' ':
token.append(' ');
break;
case '\n':
token.append('\n');
break;
default:
token.append('\\');
token.append(escapeChar);
}
}
private static Cursor lexCommand(String input, int cursor, List<Token> tokens)
{
int start = 0;
StringBuilder token = new StringBuilder();
Cursor pointer = null;
LexerState state = LexerState.NORMAL;
for (int i = 0; i < input.length(); i++)
{
if (i == cursor)
pointer = new Cursor(tokens.size(), token.length());
switch (state) {
case NORMAL:
if (input.charAt(i) == '\'')
state = LexerState.SINGLE_QUOTE;
else if (input.charAt(i) == '\"')
state = LexerState.DOUBLE_QUOTE;
else if (input.charAt(i) == '\\')
state = LexerState.NORMAL_ESCAPE;
else if (Character.isWhitespace(input.charAt(i))) {
if (token.length() > 0)
tokens.add(new Token(token.toString(), start, i - start));
token = new StringBuilder();
start = i + 1;
} else
token.append(input.charAt(i));
break;
case SINGLE_QUOTE:
if (input.charAt(i) == '\'')
state = LexerState.NORMAL;
else
token.append(input.charAt(i));
break;
case DOUBLE_QUOTE:
if (input.charAt(i) == '\"')
state = LexerState.NORMAL;
else if (input.charAt(i) == '\\')
state = LexerState.QUOTE_ESCAPE;
else
token.append(input.charAt(i));
break;
case NORMAL_ESCAPE:
escape(token, input.charAt(i));
state = LexerState.NORMAL;
break;
case QUOTE_ESCAPE:
escape(token, input.charAt(i));
state = LexerState.DOUBLE_QUOTE;
break;
default:
printError("Console", "parseCommand", "Unrecognized lexer state.");
}
}
if (pointer == null)
pointer = new Cursor(tokens.size(), token.length());
if (token.length() > 0)
tokens.add(new Token(token.toString(), start, input.length() - start));
return pointer;
}
private static void printTasks(
Collection<Task> tasks, boolean isRunning)
{
for (Task task : tasks) {
String module = "<null>";
if (task.getModule() != null)
module = task.getModule().getIdString() + " ("
+ task.getModule().getModuleName() + ")";
print(BLUE + BOLD + "[" + task.getId() + "]" + UNBOLD + DEFAULT);
println(" Task type: " + task.getType().toString());
println(GRAY + " module: " + DEFAULT + module);
println(GRAY + " scheduled execution: " + DEFAULT + new Date(task.getTime()));
println(GRAY + " is running: " + DEFAULT + isRunning);
println(GRAY + " reschedules: " + DEFAULT + task.reschedules());
println(GRAY + " dummy: " + DEFAULT + task.isDummy());
println(GRAY + " state: " + DEFAULT + task.getState());
}
}
public static boolean parseCommand(String line)
{
lexCommand(line, line.length(), tokens);
if (tokens.size() > 0) {
if (tokens.get(0).getToken().equals("exit"))
return false;
try {
root.run(tokens, 0);
} catch (Exception e) {
printError("Console", "parseCommand", "", e);
}
in.setUseHistory(historyEnabled.get());
if (in.getCompletors().isEmpty())
in.addCompletor(completor);
if (consoleLock.isHeldByCurrentThread())
consoleLock.unlock();
}
tokens.clear();
return true;
}
public static boolean initConsole()
{
try {
lockConsole();
in = new ConsoleReader();
in.addCompletor(completor);
CandidateListCompletionHandler handler = new CandidateListCompletionHandler();
handler.setAlwaysIncludeNewline(false);
in.setCompletionHandler(handler);
unlockConsole();
return true;
} catch (IOException e) {
printError("Core", "initConsole", "", e);
return false;
}
}
public static void runConsole()
{
try {
while (true) {
isReading = true;
String input = in.readLine(BOLD + PROMPT + UNBOLD);
isReading = false;
if (!parseCommand(input))
break;
}
} catch (IOException e) {
printError("Core", "startConsole", "", e);
}
}
private static class ConsoleCompletor implements Completor
{
private int complete(Command command, List<Token> tokens,
Cursor cursor, int tokenIndex, List<String> completions)
{
String match = "";
if (tokenIndex < tokens.size())
match = tokens.get(tokenIndex).getToken();
if (tokenIndex == cursor.getTokenIndex())
{
match = match.substring(0, cursor.getTokenPosition());
for (Command subcommand : command.getSubcommands()) {
if (subcommand.getName().startsWith(match))
completions.add(subcommand.getName() + ' ');
}
if (tokenIndex < tokens.size())
return tokens.get(tokenIndex).getSourcePosition();
else if (tokens.size() > 0)
return tokens.get(tokenIndex - 1).getSourcePosition()
+ tokens.get(tokenIndex - 1).getSourceLength() + 1;
else return 0;
} else {
int found = -1;
boolean multiple = false;
for (Command subcommand : command.getSubcommands()) {
if (subcommand.getName().equals(match)) {
int newfound = complete(subcommand, tokens, cursor,
tokenIndex + 1, completions);
if (newfound != -1)
{
if (found == -1) {
found = newfound;
} else
multiple = true;
}
}
}
if (multiple) return tokens.get(tokenIndex).getSourcePosition();
else return found;
}
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public int complete(String input, int pos, List completions)
{
List<Token> tokens = new ArrayList<Token>();
Cursor cursor = lexCommand(input, pos, tokens);
int position = complete(root, tokens, cursor, 0, completions);
if (position == -1)
return 0;
return position;
}
}
private static class ModulesCommand extends Command
{
public ModulesCommand() {
super("modules",
new AddModuleCommand(false),
new AddModuleCommand(true),
new RemoveModuleCommand(),
new LoadModulesCommand(),
new SaveModulesCommand(),
new GetModuleCommand(),
new SetModuleCommand());
}
@Override
public void run(List<Token> args, int index)
{
if (args.size() > 1) {
super.run(args, index);
return;
}
Console.lockConsole();
println(Core.getModuleCount() + " module(s).");
for (Module module : Core.getModules()) {
println(BOLD + "Module id: " + module.getIdString() + UNBOLD);
println(GRAY + " name: " + DEFAULT + module.getModuleName());
println(GRAY + " source: " + DEFAULT + module.getSourceName());
println(GRAY + " url: " + DEFAULT + module.getModuleUrl());
println(GRAY + " sourceurl: " + DEFAULT + module.getSourceUrl());
println(GRAY + " api: " + DEFAULT + module.getApi());
println(GRAY + " is remote: " + DEFAULT + module.isRemote());
println(GRAY + " blocked downloading: " + DEFAULT + module.blockedDownload());
println(GRAY + " active logging: " + DEFAULT + module.isLoggingActivity());
println(GRAY + " is saved: " + DEFAULT + (module.getPersistentIndex() != -1));
}
Console.unlockConsole();
}
}
private static class AddModuleCommand extends Command
{
private final boolean force;
public AddModuleCommand(boolean force) {
super(force ? "forceadd" : "add");
this.force = force;
}
private void usage() {
Console.println("usage: modules add [name] [source] [path] [url]"
+ " [sourceurl] [api:binary|json] [is remote] [use blocked downloading]");
}
private void addModule(String name, String source,
String path, String moduleUrl, String sourceUrl,
Module.Api api, boolean remote, boolean blocked)
{
long id = Core.random();
Console.lockConsole();
if (!force) {
Console.println(BOLD + "Module id: " + Core.toUnsignedString(id) + UNBOLD);
Console.println(GRAY + " name: " + DEFAULT + name);
Console.println(GRAY + " source: " + DEFAULT + source);
Console.println(GRAY + " path: " + DEFAULT + path);
Console.println(GRAY + " url: " + DEFAULT + moduleUrl);
Console.println(GRAY + " sourceurl: " + DEFAULT + sourceUrl);
Console.println(GRAY + " api: " + DEFAULT + api);
Console.println(GRAY + " is remote: " + DEFAULT + remote);
Console.println(GRAY + " use blocked downloading: " + DEFAULT + blocked);
}
try {
Boolean response = true;
if (!force) {
in.setUseHistory(false);
response = parseBoolean(in.readLine("Add this module? "));
while (response == null) {
Console.println("Must specify a boolean parameter.");
response = parseBoolean(in.readLine("Add this module? "));
}
}
if (response) {
Module module = Module.load(id, name, source, path, moduleUrl, sourceUrl, api, remote, blocked);
if (module != null && Core.addModule(module))
Console.println("Module '" + name + "' added. "
+ "Use 'modules save' to push changes to database.");
}
} catch (IOException e) {
return;
} finally {
Console.unlockConsole();
}
}
@Override
public void run(List<Token> args, int index)
{
if (args.size() > 2) {
/* parse the arguments */
if (args.size() < 8) {
Console.lockConsole();
commandError("modules add", "Too few arguments.");
usage();
Console.unlockConsole();
return;
} else if (args.size() > 10) {
Console.lockConsole();
commandError("modules add", "Too many arguments.");
usage();
Console.unlockConsole();
return;
}
String name = args.get(2).getToken();
String source = args.get(3).getToken();
String path = args.get(4).getToken();
String moduleUrl = args.get(5).getToken();
String sourceUrl = args.get(6).getToken();
Module.Api api = Module.Api.load(args.get(7).getToken());
if (api == null) {
Console.commandError("modules add", "Unrecognized API field '" + args.get(7).getToken() + "'.");
return;
}
Boolean remote = false;
if (args.size() > 8)
remote = parseBoolean(args.get(8).getToken());
Boolean blocked = true;
if (args.size() > 9)
blocked = parseBoolean(args.get(9).getToken());
if (remote == null || blocked == null) {
Console.println("[is remote] and [use blocked downloading]"
+ " must be boolean arguments.");
return;
}
addModule(name, source, path, moduleUrl, sourceUrl, api, remote, blocked);
} else {
try {
in.setUseHistory(false);
String name = in.readLine("Enter module name: ");
String source = in.readLine("Enter module source: ");
String path = in.readLine("Enter path: ");
String moduleUrl = in.readLine("Enter module URL: ");
String sourceUrl = in.readLine("Enter source URL: ");
Module.Api api = Module.Api.load(in.readLine("Enter API (binary|json): "));
if (api == null) {
Console.commandError("modules add", "Unrecognized API field.");
return;
}
Boolean remote = parseBoolean(
in.readLine("Is the module remote? "));
while (remote == null) {
Console.println("Must specify a boolean parameter.");
remote = parseBoolean(
in.readLine("Is the module remote? "));
}
Boolean blocked = parseBoolean(
in.readLine("Use blocked downloading? "));
while (blocked == null) {
Console.println("Must specify a boolean parameter.");
blocked = parseBoolean(
in.readLine("Use blocked downloading? "));
}
addModule(name, source, path, moduleUrl, sourceUrl, api, remote, blocked);
} catch (IOException e) {
commandError("modules add", "", e);
}
}
}
}
private static class GetModuleCommand extends Command
{
public GetModuleCommand() {
super("get");
}
private void usage() {
println("usage: modules get [id] [name|source|path|remote|api|blocked|activelog|url|sourceurl]");
}
@Override
public void run(List<Token> args, int index)
{
if (args.size() != 4) {
lockConsole();
commandError("modules set", "Incorrect number of arguments.");
usage();
unlockConsole();
return;
}
long id;
try {
id = new BigInteger(args.get(2).getToken()).longValue();
} catch (NumberFormatException e) {
commandError("modules set", "Unable to parse module id.");
return;
}
Module module = Core.getModule(id);
if (module == null) {
commandError("modules set", "No module found with specified id.");
return;
}
String key = args.get(3).getToken();
if (key.equals("name"))
println(module.getModuleName());
else if (key.equals("source"))
println(module.getSourceName());
else if (key.equals("path"))
println(module.getPath());
else if (key.equals("url"))
println(module.getModuleUrl());
else if (key.equals("sourceurl"))
println(module.getSourceUrl());
else if (key.equals("api"))
println(module.getApi().toString());
else if (key.equals("remote")) {
println(Boolean.toString(module.isRemote()));
} else if (key.equals("blocked")) {
println(Boolean.toString(module.blockedDownload()));
} else if (key.equals("activelog")) {
println(Boolean.toString(module.isLoggingActivity()));
}
}
}
private static class SetModuleCommand extends Command
{
public SetModuleCommand() {
super("set");
}
private void usage() {
println("usage: modules set [id] [name|source"
+ "|path|remote|blocked|api|activelog|url|sourceurl] [value]");
}
@Override
public void run(List<Token> args, int index)
{
if (args.size() != 5) {
lockConsole();
commandError("modules set", "Incorrect number of arguments.");
usage();
unlockConsole();
return;
}
long id;
try {
id = new BigInteger(args.get(2).getToken()).longValue();
} catch (NumberFormatException e) {
commandError("modules set", "Unable to parse module id.");
return;
}
Module module = Core.getModule(id);
if (module == null) {
commandError("modules set", "No module found with specified id.");
return;
}
String key = args.get(3).getToken();
String value = args.get(4).getToken();
if (key.equals("name"))
module.setModuleName(value);
else if (key.equals("source"))
module.setSourceName(value);
else if (key.equals("path"))
module.setPath(value);
else if (key.equals("url"))
module.setModuleUrl(value);
else if (key.equals("sourceurl"))
module.setSourceUrl(value);
else if (key.equals("api")) {
module.setApi(Module.Api.load(value));
} else if (key.equals("remote")) {
Boolean parsed = parseBoolean(value);
if (parsed != null)
module.setRemote(parsed);
else {
commandError("modules set", "Unable to parse boolean parameter.");
}
} else if (key.equals("blocked")) {
Boolean parsed = parseBoolean(value);
if (parsed != null)
module.setBlockedDownload(parsed);
else {
commandError("modules set", "Unable to parse boolean parameter.");
}
} else if (key.equals("activelog")) {
Boolean parsed = parseBoolean(value);
if (parsed != null)
module.setLoggingActivity(parsed);
else {
commandError("modules set", "Unable to parse boolean parameter.");
}
}
}
}
private static class SaveModulesCommand extends Command
{
public SaveModulesCommand() {
super("save");
}
@Override
public void run(List<Token> args, int index)
{
if (Core.saveModules())
println("Successfully saved " + Core.getModuleCount() + " modules.");
else
commandError("modules save", "Error occurred while saving modules.");
}
}
private static class RemoveModuleCommand extends Command
{
public RemoveModuleCommand() {
super("remove");
}
private void usage() {
println("usage: modules remove [id]");
}
@Override
public void run(List<Token> args, int index)
{
if (args.size() != 3) {
lockConsole();
commandError("modules remove", "Incorrect number of arguments.");
usage();
unlockConsole();
return;
}
long id;
try {
id = new BigInteger(args.get(2).getToken()).longValue();
} catch (NumberFormatException e) {
commandError("modules remove", "Unable to parse module id.");
return;
}
Module module = Core.getModule(id);
if (module == null) {
commandError("modules remove", "No module found with specified id.");
return;
}
if (!Core.removeModule(module))
commandError("modules remove", "Could not remove module.");
}
}
private static class LoadModulesCommand extends Command
{
public LoadModulesCommand() {
super("load");
}
@Override
public void run(List<Token> args, int index)
{
if (!Core.loadModules())
commandError("modules load", "Error occurred while loading modules.");
}
}
private static class TasksCommand extends Command
{
public TasksCommand() {
super("tasks",
new LoadTasksCommand(),
new SaveTasksCommand(),
new QueuedTasksCommand(),
new RunningTasksCommand(),
new AddTaskCommand(true),
new AddTaskCommand(false),
new RemoveTaskCommand());
}
@Override
public void run(List<Token> args, int index)
{
if (args.size() > 1) {
super.run(args, index);
return;
}
List<Task> queued = Core.getQueuedTasks();
List<Task> running = Core.getRunningTasks();
Collections.sort(queued);
Collections.sort(running);
Console.lockConsole();
println((queued.size() + running.size()) + " total task(s).");
printTasks(queued, false);
printTasks(running, true);
Console.unlockConsole();
}
}
private static class LoadTasksCommand extends Command
{
public LoadTasksCommand() {
super("load");
}
@Override
public void run(List<Token> args, int index)
{
if (!Core.loadQueue())
commandError("tasks load", "Error occurred while loading tasks.");
}
}
private static class SaveTasksCommand extends Command
{
public SaveTasksCommand() {
super("save");
}
@Override
public void run(List<Token> args, int index)
{
if (Core.saveQueue())
println("Successfully saved " + Core.getTaskCount() + " tasks.");
else
commandError("tasks save", "Error occurred while saving tasks.");
}
}
private static class QueuedTasksCommand extends Command
{
public QueuedTasksCommand() {
super("queued");
}
@Override
public void run(List<Token> args, int index)
{
List<Task> queued = Core.getQueuedTasks();
Collections.sort(queued);
Console.lockConsole();
println(queued.size() + " task(s) queued.");
printTasks(queued, false);
Console.unlockConsole();
}
}
private static class RunningTasksCommand extends Command
{
public RunningTasksCommand() {
super("running");
}
@Override
public void run(List<Token> args, int index)
{
List<Task> running = Core.getRunningTasks();
Collections.sort(running);
Console.lockConsole();
println(running.size() + " task(s) running.");
printTasks(running, true);
Console.unlockConsole();
}
}
private static class AddTaskCommand extends Command
{
private final boolean force;
public AddTaskCommand(boolean force) {
super(force ? "forceadd" : "add");
this.force = force;
}
private void usage() {
Console.println("usage: tasks add [parse type] [module id]"
+ " [start time] [reschedules] [dummy] [state]");
Console.println(" [parse type] can either be 'info', 'list', or 'image'.");
Console.println(" [start time] must be an integer indicating milliseconds from now.");
Console.println(" [dummy] indicates whether information is written to the database.");
Console.println(" [state] is the state data passed to the module.");
Console.println(" By default, reschedules is false, dummy is true, and state is empty.");
}
private void addTask(TaskType type, Module module, long time,
boolean reschedules, boolean dummy, String state)
{
Console.lockConsole();
if (!force) {
Console.println(BOLD + "Task type: " + type.toString() + UNBOLD);
Console.println(GRAY + " module id: " + DEFAULT + module.getIdString());
Console.println(GRAY + " module name: " + DEFAULT + module.getModuleName());
Console.println(GRAY + " time: " + DEFAULT + new Date(time).toString());
Console.println(GRAY + " reschedules: " + DEFAULT + reschedules);
Console.println(GRAY + " is dummy: " + DEFAULT + dummy);
if (state != null)
Console.println(GRAY + " state: " + DEFAULT + state);
}
try {
Boolean response = true;
if (!force) {
response = parseBoolean(in.readLine("Add this task? "));
in.setUseHistory(false);
while (response == null) {
Console.println("Must specify a boolean parameter.");
response = parseBoolean(in.readLine("Add this task? "));
}
}
if (response) {
Task task = new Task(type, module, time, reschedules, dummy, state);
if (task != null) {
Core.queueTask(task);
Console.println("Task queued. "
+ "Use 'tasks save' to push changes to database.");
}
}
} catch (IOException e) {
return;
} finally {
Console.unlockConsole();
}
}
@Override
public void run(List<Token> args, int index)
{
if (args.size() > 2) {
if (args.size() < 5) {
lockConsole();
commandError("tasks add", "Too few arguments.");
usage();
unlockConsole();
return;
}
String typeString = args.get(2).getToken().toLowerCase();
TaskType type;
if (typeString.equals("list")) {
type = TaskType.PRODUCT_LIST_PARSE;
} else if (typeString.equals("info")) {
type = TaskType.PRODUCT_INFO_PARSE;
} else if (typeString.equals("image")) {
type = TaskType.IMAGE_FETCH;
} else {
lockConsole();
commandError("tasks add", "Unable to parse task type.");
usage();
unlockConsole();
return;
}
long id;
try {
id = new BigInteger(args.get(3).getToken()).longValue();
} catch (NumberFormatException e) {
commandError("tasks add", "Unable to parse time.");
return;
}
Module module = Core.getModule(id);
if (module == null) {
commandError("tasks add", "No module found with specified id.");
return;
}
int time;
try {
time = Integer.parseInt(args.get(4).getToken());
} catch (NumberFormatException e) {
commandError("tasks add", "Unable to parse module id.");
return;
}
Boolean reschedules = false;
if (args.size() > 5)
reschedules = parseBoolean(args.get(5).getToken());
Boolean dummy = true;
if (args.size() > 6)
dummy = parseBoolean(args.get(6).getToken());
if (reschedules == null || dummy == null) {
Console.println("[is remote] and [use blocked downloading]"
+ " must be boolean arguments.");
return;
}
String state = null;
if (args.size() > 7)
state = args.get(7).getToken();
addTask(type, module, System.currentTimeMillis()
+ time, reschedules, dummy, state);
} else {
try {
in.setUseHistory(false);
String typeString = in.readLine("Enter task type: (list|info|image) ").toLowerCase();
TaskType type;
if (typeString.equals("list")) {
type = TaskType.PRODUCT_LIST_PARSE;
} else if (typeString.equals("info")) {
type = TaskType.PRODUCT_INFO_PARSE;
} else if (typeString.equals("image")) {
type = TaskType.IMAGE_FETCH;
} else {
lockConsole();
commandError("tasks add", "Unable to parse task type.");
usage();
unlockConsole();
return;
}
long id;
try {
id = new BigInteger(in.readLine("Enter module id: ")).longValue();
} catch (NumberFormatException e) {
commandError("tasks add", "Unable to parse module id.");
return;
}
Module module = Core.getModule(id);
if (module == null) {
commandError("tasks add", "No module found with specified id.");
return;
}
int time;
try {
time = Integer.parseInt(in.readLine(
"Enter scheduled time (in ms from now): "));
} catch (NumberFormatException e) {
commandError("tasks add", "Unable to time.");
return;
}
Boolean reschedules = parseBoolean(in.readLine(
"Does this task automatically reschedule? "));
while (reschedules == null) {
Console.println("Must specify a boolean parameter.");
reschedules = parseBoolean(in.readLine(
"Does this task automatically reschedule? "));
}
Boolean dummy = parseBoolean(in.readLine(
"Disable writing to the database? "));
while (dummy == null) {
Console.println("Must specify a boolean parameter.");
dummy = parseBoolean(in.readLine(
"Disable writing to the database? "));
}
String state = in.readLine("Enter initial module state (or leave empty): ");
if (state.length() == 0)
state = null;
addTask(type, module, System.currentTimeMillis()
+ time, reschedules, dummy, state);
} catch (IOException e) {
commandError("modules add", "", e);
}
}
}
}
private static class RemoveTaskCommand extends Command
{
public RemoveTaskCommand() {
super("remove");
}
private void usage() {
println("usage: tasks remove [id]");
}
@Override
public void run(List<Token> args, int index)
{
if (args.size() != 3) {
lockConsole();
commandError("tasks remove", "Incorrect number of arguments.");
usage();
unlockConsole();
return;
}
int id;
try {
id = Integer.parseInt(args.get(2).getToken());
} catch (NumberFormatException e) {
commandError("tasks remove", "Unable to parse task id.");
return;
}
Task task = Task.getTask(id);
if (task == null) {
commandError("tasks remove", "No task found with specified id.");
return;
}
Core.stopTask(task, true);
}
}
private static class HistoryCommand extends Command
{
public HistoryCommand() {
super("history");
}
private void usage() {
println("usage: history on [optional:file]");
println(" history off");
}
@Override
public void run(List<Token> args, int index)
{
if (args.size() < 2) {
commandError("history", "Too few arguments.");
usage();
return;
}
Boolean on = parseBoolean(args.get(1).getToken());
if (on == null) {
commandError("history", "Unable to parse boolean parameter.");
return;
}
if (on) {
if (args.size() == 3) {
String filename = args.get(2).getToken();
File file = new File(filename);
if (!file.exists()) {
try {
if (!file.createNewFile()) {
commandError("history",
"Cannot create file '" + filename + "'.");
return;
}
} catch (IOException e) {
commandError("history", "", e);
return;
}
} else if (!file.canRead() || !file.canWrite()) {
commandError("history", "No read/write access"
+ " to given file '" + filename + "'.");
return;
}
try {
in.getHistory().setHistoryFile(file);
} catch (IOException e) {
commandError("history", "", e);
return;
}
} else if (args.size() > 3) {
commandError("history", "Too many arguments.");
usage();
return;
}
/* only turn on history if there are no errors */
historyEnabled.set(true);
in.setUseHistory(true);
} else {
historyEnabled.set(false);
in.setUseHistory(false);
}
}
}
private static class MigrateCommand extends Command
{
public MigrateCommand() {
super("migrate");
}
@Override
public void run(List<Token> args, int index)
{
HashSet<String> strings = new HashSet<String>();
try {
Reader r = new InputStreamReader(
new BufferedInputStream(new FileInputStream("Entity.sql")));
boolean QUOTE_STATE = false;
StringBuilder b = new StringBuilder();
boolean done = false;
while (!done) {
int c = r.read();
switch (c) {
case -1:
if (QUOTE_STATE)
System.err.println("Should not end in the quote state...");
done = true;
break;
case '\'':
if (QUOTE_STATE) {
strings.add(b.toString());
b = new StringBuilder();
}
QUOTE_STATE = !QUOTE_STATE;
break;
default:
if (QUOTE_STATE)
b.append((char) c);
}
}
r.close();
} catch (IOException e) {
e.printStackTrace();
return;
}
/* find the newegg module */
Module newegg = null;
for (Module m : Core.getModules()) {
if (m.getModuleName().equals("Newegg Parser"))
newegg = m;
}
if (newegg == null) {
commandError("migrate", "Could not find module 'Newegg Parser'.");
return;
}
String[] strarr = new String[strings.size()];
strarr = strings.toArray(strarr);
if (Core.getDatabase() != null)
Core.getDatabase().addProductIds(newegg, strarr);
}
}
private static class TestServerCommand extends Command
{
public TestServerCommand() {
super("testserver");
}
@Override
public void run(List<Token> args, int index)
{
try {
String query = "raid";
if (args.size() > 1)
query = args.get(1).getToken();
String limit = "15";
if (args.size() > 2)
limit = args.get(2).getToken();
String page = "1";
if (args.size() > 3)
page = args.get(3).getToken();
URLConnection connection = new URL("http://localhost:16317/search" /*"http://140.180.186.131:16317"*/).openConnection();
HttpURLConnection http = (HttpURLConnection) connection;
http.setDoInput(true);
http.setDoOutput(true);
http.setUseCaches(false);
http.setRequestMethod("GET");
http.connect();
http.getOutputStream().write(
("{\"select\":[\"gid\",\"url\"],"
+ " \"name\":\"" + query + "\","
+ " \"page\":\"" + page + "\","
+ " \"pagesize\":" + limit + "}").getBytes());
//http.getOutputStream().write(
// ("{\"gid\":0}").getBytes());
http.getOutputStream().flush();
http.getOutputStream().close();
InputStream input = http.getInputStream();
while (true) {
int c = input.read();
if (c == -1) break;
AnsiConsole.out.print((char) c);
}
input.close();
Console.printError("TEST","TEST","checkPrice: " + Core.checkPrice(Core.getModules().get(0), 0, 1000));
} catch (IOException e) {
Console.commandError("testserver", "", e);
}
}
}
private static class TriggersCommand extends Command
{
public TriggersCommand() {
super("triggers");
}
private void printInfo(long gid, PriceTrigger info) {
if (info == null) {
println("No triggers found.");
return;
}
println(BOLD + "Trigger gid = "
+ Core.toUnsignedString(gid) + ":" + UNBOLD);
println(GRAY + " count: " + DEFAULT + info.getNumTracks());
for (Entry<Long, PriceTrack> entry : info.getModuleTracks().entrySet())
println(GRAY + " module trigger (id = "
+ Core.toUnsignedString(entry.getKey()) + ") count: "
+ DEFAULT + entry.getValue().getNumTracks());
PriceTrigger.printInfo(info.getThresholdTracks(), " ");
for (Entry<Long, TreeSet<PriceTrack>> entry
: info.getModuleThresholdTracks().entrySet())
{
println(GRAY + " module trigger (id = "
+ Core.toUnsignedString(entry.getKey()) + "): " + DEFAULT);
PriceTrigger.printInfo(entry.getValue(), " ");
}
}
@Override
public void run(List<Token> args, int index)
{
Long gid = null;
try {
if (args.size() > 1)
gid = new BigInteger(args.get(1).getToken()).longValue();
else {
commandError("triggers", "Incorrect number of arguments. Expected single gid parameter.");
return;
}
} catch (NumberFormatException e) {
commandError("triggers", "Unable to parse gid.");
return;
}
lockConsole();
if (gid != null) {
PriceTrigger info = Core.getPriceTrigger(gid);
printInfo(gid, info);
}
unlockConsole();
}
}
private static class ImageQueueCommand extends Command
{
public ImageQueueCommand() {
super("imagequeue");
}
@Override
public void run(List<Token> args, int index)
{
lockConsole();
println(GRAY + " queue start: " + DEFAULT + Core.getImageQueueStart());
println(GRAY + " queue end: " + DEFAULT + Core.getImageQueueEnd());
unlockConsole();
}
}
private static class ExitCommand extends Command
{
public ExitCommand() {
super("exit");
}
}
}
class Cursor
{
private int tokenIndex;
private int tokenPos;
public Cursor(int tokenIndex, int tokenPosition) {
this.tokenIndex = tokenIndex;
this.tokenPos = tokenPosition;
}
public int getTokenIndex() {
return this.tokenIndex;
}
public int getTokenPosition() {
return this.tokenPos;
}
}
class Command
{
private String name;
private Command[] subcommands;
public Command(String name) {
this.name = name;
this.subcommands = new Command[0];
}
public Command(String name, Command... subcommands) {
this.name = name;
this.subcommands = subcommands;
}
public String getName() {
return name;
}
public Command[] getSubcommands() {
return subcommands;
}
private void getCommandPrefix(
StringBuilder builder, List<Token> args, int index)
{
if (index > 0) {
for (int i = 0; i < index - 1; i++) {
builder.append(args.get(i).getToken());
builder.append(" ");
}
builder.append(args.get(index - 1).getToken());
builder.append(": ");
}
}
public void run(List<Token> args, int index)
{
String token = "";
if (index < args.size())
token = args.get(index).getToken();
else {
StringBuilder builder = new StringBuilder();
getCommandPrefix(builder, args, index - 1);
builder.append("Command '");
builder.append(args.get(index - 1).getToken());
builder.append("' not implemented.");
Console.println(builder.toString());
return;
}
for (Command subcommand : subcommands) {
if (subcommand.getName().equals(token)) {
subcommand.run(args, index + 1);
return;
}
}
StringBuilder builder = new StringBuilder();
getCommandPrefix(builder, args, index);
builder.append("Unrecognized command '");
builder.append(args.get(index).getToken());
builder.append("'.");
Console.println(builder.toString());
}
}
class Token {
private String token;
private int sourcePos;
private int sourceLength;
public Token (String token, int sourcePosition, int sourceLength) {
this.token = token;
this.sourcePos = sourcePosition;
this.sourceLength = sourceLength;
}
public String getToken() {
return token;
}
public int getSourcePosition() {
return sourcePos;
}
public int getSourceLength() {
return sourceLength;
}
}
enum LexerState {
NORMAL,
SINGLE_QUOTE,
DOUBLE_QUOTE,
NORMAL_ESCAPE,
QUOTE_ESCAPE
}